package com.halden.mycache.support.EvictStrategy.impl;

import com.halden.mycache.support.EvictStrategy.ICacheEvictContext;
import com.halden.mycache.core.Impl.CacheValue;
import com.halden.mycache.core.Impl.MyCache;
import com.halden.mycache.support.listener.CacheRemoveContext;
import com.halden.mycache.support.listener.RemoveType;
import lombok.extern.slf4j.Slf4j;

/**
 * @Author: halden
 * @Data:2023/2/3 10:39
 * @Description: 对value的包装类
 * @since 0.0.1
 */
@Slf4j
public class LFUStrategy<K,V> extends AbstractEvictStrategy<K,V> {

    /**
     * 仿照redis的LFU，随机选取5个成员，淘汰其中使用频率最低的
     * @param context
     * @since 0.0.1
     */
    public void evict(ICacheEvictContext<K, V> context) {
        MyCache<K, V> cache = context.getCache();
        int length = cache.getLength();
        // 如果是新增并且超过了内存大小限制，需要进行淘汰
        log.info("进行内存淘汰");
        // 随机抽取内存中的5个元素
        Integer[] integers = random5Num(length);
        K[] keys = (K[]) cache.keySet().toArray();
        K key = null;
        double frequency = Integer.MAX_VALUE;
        // 遍历元素，找出其中访问频次最小的元素
        for (Integer i : integers){
            // 使用simpleGet不修改该元素的最后访问时间与访问频率
            CacheValue<V> cacheValue = cache.simpleGet(keys[i]);
            // 如果发现了过期元素，直接返回
            // 在checkExpire方法中已经将过期元素删除
            cache.checkExpire(keys[i], cacheValue);
            double visitFrequency = cacheValue.getVisitFrequency();
            if (visitFrequency < frequency){
                frequency = visitFrequency;
                key = keys[i];
            }
        }
        //已经剔除了过期元素，空间解放，无须淘汰内存
        length = cache.getLength();
        if (length < cache.getSize()){
            return;
        }
        // 将找到的元素删除，完成内存淘汰
        cache.remove(key, new CacheRemoveContext<>(key, cache.simpleGet(key).getValue(), RemoveType.EVICT_REMOVE));
    }

}
